﻿using System;
using Sunny.Core.Exception;

namespace Sunny.Core.DefinedData
{
    [Serializable]
    public struct SDateTime : IComparable<SDateTime>
    {
        private readonly DateTime? _dateTime;

        public SDateTime(DateTime? value)
        {
            _dateTime = value;
        }

        #region Implicit Operator WebEziDateTime

        public static implicit operator SDateTime(string value)
        {
            if (String.IsNullOrEmpty(value))
            {
                return new SDateTime(null);
            }
            else
            {
                DateTime dateTime;
                if (DateTime.TryParse(value, out dateTime))
                {
                    return new SDateTime(DateTime.Parse(value));
                }
                else
                {
                    throw new DefinedDataException("The source value is " + value);
                }
            }
        }

        public static implicit operator SDateTime(DateTime? value)
        {
            return new SDateTime(value);
        }

        #endregion

        #region Implicit Operator Other

        public static implicit operator DateTime?(SDateTime value)
        {
            return value._dateTime;
        }

        public static implicit operator DateTime(SDateTime value)
        {
            if (!value._dateTime.HasValue)
            {
                throw new DefinedDataException("The datetime is null, can't convert to datetime.");
            }

            return value._dateTime.Value;
        }

        public static implicit operator string(SDateTime value)
        {
            if (value._dateTime.HasValue)
            {
                return value._dateTime.Value.ToString();
            }
            else
            {
                return string.Empty;
            }
        }

        #endregion

        #region Implicit Operator

        public static bool operator ==(SDateTime x, SDateTime y)
        {
            return x._dateTime == y._dateTime;
        }

        public static bool operator !=(SDateTime x, SDateTime y)
        {
            return x._dateTime != y._dateTime;
        }

        public static bool operator <(SDateTime x, SDateTime y)
        {
            return x._dateTime < y._dateTime;
        }

        public static bool operator >(SDateTime x, SDateTime y)
        {
            return x._dateTime > y._dateTime;
        }

        public static bool operator <=(SDateTime x, SDateTime y)
        {
            return x._dateTime <= y._dateTime;
        }

        public static bool operator >=(SDateTime x, SDateTime y)
        {
            return x._dateTime >= y._dateTime;
        }

        public static bool operator ==(SDateTime x, DateTime y)
        {
            return x._dateTime == y;
        }

        public static bool operator !=(SDateTime x, DateTime y)
        {
            return x._dateTime != y;
        }

        public static bool operator <(SDateTime x, DateTime y)
        {
            return x._dateTime < y;
        }

        public static bool operator >(SDateTime x, DateTime y)
        {
            return x._dateTime > y;
        }

        public static bool operator <=(SDateTime x, DateTime y)
        {
            return x._dateTime <= y;
        }

        public static bool operator >=(SDateTime x, DateTime y)
        {
            return x._dateTime >= y;
        }

        #endregion

        /// <summary>
        /// Return the value is null or empty
        /// </summary>
        /// <returns>The value is null or empty</returns>
        public bool IsNull()
        {
            return !_dateTime.HasValue;
        }

        public override string ToString()
        {
            if (_dateTime.HasValue)
            {
                return _dateTime.Value.ToString();
            }
            else
            {
                return string.Empty;
            }
        }

        public string ToString(string format)
        {
            if (_dateTime.HasValue)
            {
                return _dateTime.Value.ToString(format);
            }
            else
            {
                return string.Empty;
            }
        }

        public string ToShortDateString()
        {
            return _dateTime.Value.ToShortDateString();
        }

        public string ToShortTimeString()
        {
            if (_dateTime.HasValue)
            {
                return _dateTime.Value.ToShortTimeString();
            }
            else
            {
                return string.Empty;
            }
        }

        public string ToLongDateString()
        {
            if (_dateTime.HasValue)
            {
                return _dateTime.Value.ToLongDateString();
            }
            else
            {
                return string.Empty;
            }
        }

        public string ToLongTimeString()
        {
            if (_dateTime.HasValue)
            {
                return _dateTime.Value.ToLongTimeString();
            }
            else
            {
                return string.Empty;
            }
        }

        public DateTime ToDateTime()
        {
            if (_dateTime.HasValue)
            {
                return _dateTime.Value;
            }
            else
            {
                return new DateTime();
            }
        }

        #region IComparable<WebEziDateTime> Members

        public int CompareTo(SDateTime other)
        {
            if (_dateTime.HasValue)
            {
                return _dateTime.Value.CompareTo(other._dateTime);
            }
            else if (!other._dateTime.HasValue)
            {
                return 0;
            }
            else
            {
                return -1;
            }
        }

        #endregion

        public bool Equals(SDateTime obj)
        {
            return obj._dateTime.Equals(_dateTime);
        }

        public override bool Equals(object obj)
        {
            if (obj.GetType() != typeof (SDateTime)) return false;
            return Equals((SDateTime) obj);
        }

        public override int GetHashCode()
        {
            return (_dateTime.HasValue ? _dateTime.Value.GetHashCode() : 0);
        }
    }
}
